home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / heapdbg.zip / HEAP.DBG < prev   
Text File  |  1990-01-17  |  22KB  |  720 lines

  1. *********************************README.1ST**********************************
  2.  
  3. Here is a list of the files following this introduction:
  4.  
  5. MAIN.C      : A sample program to demonstrate the heap debugging stuff
  6. HEAP.H      : The header file that turns on the debugging stuff
  7. HEAP.C      : The routines that comprise the heap debugger
  8. SCREEN.C    : The routines to dump debugging information to the screen.
  9.               This is the code that is machine/operating system dependent.
  10. _HEAP.H     : A private header file for the debugging routines.
  11.  
  12. *********************************MAIN.C*****************************************
  13. /*
  14.  * Author:       Mark Nelson
  15.  *
  16.  * Date:         October 28, 1989
  17.  *
  18.  * Description:  This is the main() module used to test the heap
  19.  *               debugger routines.  It does a few different
  20.  *               things that should be detected by the debugger
  21.  *               routines.
  22.  */
  23.  
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include "heap.h"
  27.  
  28. void main( void )
  29. {
  30.     char *test_guy_1;
  31.     char *test_guy_2;
  32.     char *test_guy_3;
  33.     char *maverick_pointer;
  34.  
  35.     test_guy_1 = malloc( 1000 );
  36.     test_guy_2 = malloc( 2000 );
  37. /*
  38.  * This call to strdup creates a maverick pointer that I should detect
  39.  * next time I get into my debugger routines.
  40.  */
  41.     maverick_pointer = strdup( "This is a test" );
  42.     test_guy_3 = malloc( 3000 );
  43. /*
  44.  *  Here I write one byte past my allocated area.  This should create a
  45.  *  picket error.
  46.  */
  47.     test_guy_2[ 2000 ] = 'X';
  48.     free( test_guy_1 );
  49.     free( maverick_pointer );
  50.     free( test_guy_2 );
  51.     free( test_guy_3 );
  52. }
  53.  
  54. *********************************HEAP.H*****************************************
  55.  
  56. #define malloc(size) my_malloc(__FILE__,__LINE__,(size))
  57. #define calloc(nitems,size) my_calloc(__FILE__,__LINE__,(nitems),(size))
  58. #define free(block)  my_free(__FILE__,__LINE__,(block))
  59.  
  60. void *my_malloc(char *file_name,unsigned int line_number,size_t size);
  61. void *my_calloc(char *file_name,unsigned int line_number,size_t nitems,size_t size);
  62. void my_free(char *file_name,unsigned int line_number, void *block);
  63.  
  64. /* Prototypes from SCREEN.C  */
  65.  
  66. void draw_boxes_and_titles(char *labels[],int row_count);
  67. void screenputc(int row,int col,char c);
  68. void screenputf(int row,int col,char *format,...);
  69. void screenputs(int row,int col,char *string);
  70. void screenclearline(int row);
  71. void initialize_screen(char *labels[],int widths[]);
  72. void setup_screen(char *labels[],int widths[],int rows);
  73. void restore_screen(void);
  74.  
  75. /* Prototypes from HEAP.C */
  76.  
  77. void screen_message(int immediate_return, int tag, char *format,...);
  78. void hide_screen(void);
  79. void my_free(char *file_name,unsigned int line_number, void *block);
  80. void *my_malloc(char *file_name,unsigned int line_number,size_t size);
  81. void initialize_tags(void);
  82. void display_tag_table(int last_tag);
  83. void add_tag_to_table(char far *pointer,char maverick,size_t size,char *file_name,unsigned int line_number);
  84. void delete_tag_from_table(int tag);
  85. void verify_heap(void);
  86. void heap_walk(void);
  87. *********************************HEAP.C*****************************************
  88.  
  89. /*
  90.  * Author:       Mark Nelson
  91.  *
  92.  * Date:         October 28, 1989
  93.  *
  94.  * Description:  This module contains the replacement routines used
  95.  *               to debug heap problems.  The routines are used in
  96.  *               conjunction with the HEAP.H header file.
  97.  */
  98. #include <stdio.h>
  99. #include <stdlib.h>
  100. #include <stdarg.h>
  101. #include <malloc.h>
  102. #include <conio.h>
  103. #include "_heap.h"
  104.  
  105. /*
  106.  * This structure defines all the fields that I use in the tag
  107.  * table database.
  108.  */
  109. #define TAG_MAX 100
  110.  
  111. struct tags {
  112.                 char far * returned_address;
  113.                 char far * real_address;
  114.                 size_t size;
  115.                 char *file_name;
  116.                 unsigned int line_number;
  117.                 char maverick;
  118.                 char tagged;
  119.             } tag_table[TAG_MAX];
  120.  
  121. int next_free_tag = -1;
  122.  
  123.  
  124. /*
  125.  * These are some odds and ends I use all around.
  126.  */
  127. char leading_picket[] = "0123456789ABCDE";
  128. char trailing_picket[] = "FEDCBA987654321";
  129. #define PICKET_SIZE sizeof( leading_picket )
  130.  
  131.  
  132. /*
  133.  * These are the labels and widths for each of the columns in the output
  134.  * screen.
  135.  */
  136. char *labels[]={"Tag #","File Name","Line #","Picket","Address","Size","Picket",""};
  137. int widths[]={5,12,6,15,9,6,15};
  138. extern int columns[];
  139. int screen_up=0;
  140. int message_line;
  141.  
  142.  
  143. /*
  144.  * This is the my_malloc routine that replaces malloc().  Before it does
  145.  * anything else, it performs the heap checkout stuff.  This will pop up
  146.  * a message if anything funny is detected.  It then gets the pointer
  147.  * for the caller, and adds it to the tag table.  The screen is then
  148.  * cleared up, and the pointer is returned.
  149.  */
  150.  
  151. void *my_malloc(char *file_name,unsigned int line_number,size_t size)
  152. {
  153.   void *malloc_pointer;
  154.   size_t real_size;
  155.  
  156.   verify_heap();
  157.   real_size = size + PICKET_SIZE*2;
  158.   malloc_pointer = malloc( real_size );
  159.   if ( malloc_pointer == NULL ) {
  160.     screen_message( 1, 0, "File: %s Line: %u requesting %u bytes",
  161.                     file_name, line_number, size );
  162.     screen_message( 0, 0, "Malloc failed! Null pointer will be returned." );
  163.   }
  164.   else
  165.     add_tag_to_table( malloc_pointer, 0, size, file_name, line_number );
  166.   hide_screen();
  167.   return( ( char * ) malloc_pointer + PICKET_SIZE );
  168. }
  169.  
  170.  
  171. /*
  172.  * my_free is set up to replace free().  Just like my_malloc(), it first
  173.  * checks out the heap and prints a message if anything funny shows up.
  174.  * Before I try to free the block, I have to check and see if it is in
  175.  * my tag table.  If it is, I free the real pointer, not the one I passed
  176.  * back to the caller.  If it isn't in the tag table, I print a message
  177.  * out to that effect, and return.
  178.  */
  179.  
  180. void my_free( char *file_name, unsigned int line_number, void *block )
  181. {
  182.   int tag;
  183.  
  184.   verify_heap();
  185.   for ( tag = 0; tag < TAG_MAX ; tag++ ) {
  186.     if ( tag_table[ tag ].returned_address == ( void far * ) block )
  187.       break;
  188.   }
  189.   if ( tag < TAG_MAX ) {
  190.     if ( tag_table[ tag ].maverick ) {
  191.         screen_message( 1, 0, "File: %s Line: %u freeing block %Fp",
  192.                         file_name, line_number, ( void far * ) block );
  193.         screen_message( 0, 0, "Tag is a maverick entry!" );
  194.         free( block );
  195.     }
  196.     else
  197.         free( ( char * ) block - PICKET_SIZE );
  198.     delete_tag_from_table( tag );
  199.   }
  200.   else {
  201.     screen_message( 1, 0, "File: %s Line: %u freeing block %Fp",
  202.                     file_name, line_number, ( void far * ) block );
  203.     screen_message( 0, 0, "Tag was not found in tag table!  Going to try and free() it." );
  204.     free( block );
  205.     screen_message( 0, 0, "Heap after freeing anonymous block!" );
  206.   }
  207.   hide_screen();
  208. }
  209.  
  210.  
  211. /*
  212.  * I need to initialize the tag table my first time through.  This
  213.  * routine gets called all the time, but only performs the initialization
  214.  * once, when next_free_tag is -1.
  215.  */
  216.  
  217. void initialize_tags()
  218. {
  219.   int i;
  220.  
  221.   if ( next_free_tag == -1 ) {
  222.     next_free_tag = 0;
  223.     for ( i = 0 ; i < TAG_MAX ; i++ ) {
  224.       tag_table[ i ].returned_address = NULL;
  225.       tag_table[ i ].file_name = "Not in use";
  226.       tag_table[ i ].line_number = 0;
  227.       tag_table[ i ].size = 0;
  228.     }
  229.   }
  230. }
  231.  
  232.  
  233. /*
  234.  * This is the routine called to display the tag table when something
  235.  * has gone wrong.  It sits in a loop displaying tag table entries, 15
  236.  * at a time.  The user can hit the 'u' or 'd' keys to move up or down
  237.  * in the table.  Any other key breaks the user out.
  238.  */
  239.  
  240. void display_tag_table( int last_tag )
  241. {
  242.   int first_tag;
  243.   int offset;
  244.   int tag;
  245.   char far *picket_pointer;
  246.   int key;
  247.  
  248.   if ( last_tag < 16 )
  249.     first_tag = 0;
  250.   else
  251.     first_tag = last_tag - 15;
  252.  
  253.     for ( ; ; ) {
  254.     for ( offset = 0 ; offset < 15 ; offset++ ) {
  255.       tag = first_tag + offset;
  256.       screenputf( offset + 3, columns[ 0 ] + 1, "%-3d", tag );
  257.       screenputf( offset + 3, columns[ 1 ] + 1, "%-12s",
  258.                   tag_table[ tag ].file_name );
  259.       screenputf( offset + 3, columns[ 2 ] + 1, "%-5d",
  260.                   tag_table[ tag ].line_number );
  261.       if ( tag_table[ tag ].returned_address != NULL ) {
  262.         picket_pointer = tag_table[ tag ].returned_address;
  263.         picket_pointer -= PICKET_SIZE ;
  264.         if ( tag_table[ tag ].maverick )
  265.           screenputf( offset + 3, columns[ 3 ] + 1,"%15s", "***MAVERICK***" );
  266.         else
  267.           screenputf( offset + 3, columns[ 3 ] + 1, "%15s", picket_pointer );
  268.         screenputf( offset + 3, columns[ 4 ] + 1, "%Fp",
  269.                     tag_table[ tag ].returned_address );
  270.         picket_pointer += PICKET_SIZE;
  271.         picket_pointer += tag_table[ tag ].size;
  272.         if ( tag_table[ tag ].maverick )
  273.           screenputf( offset + 3, columns[ 6 ] + 1, "%15s", "***MAVERICK***" );
  274.         else
  275.           screenputf( offset + 3, columns[ 6 ] + 1, "%15s", picket_pointer );
  276.       }
  277.       else {
  278.         screenputf( offset + 3, columns[ 3 ] + 1, "%15s", "" );
  279.         screenputf( offset + 3, columns[ 4 ] + 1, "  NULL   " );
  280.         screenputf( offset + 3, columns[ 6 ] + 1, "%15s", "" );
  281.       }
  282.       screenputf( offset + 3, columns[ 5 ] + 1, "%-5d", tag_table[ tag ].size );
  283.     }
  284.     key = getch();
  285.     if ( key == 'u' || key == 'U' ) {
  286.         first_tag -= 15;
  287.         if (first_tag < 0)
  288.           first_tag = 0;
  289.     }
  290.     else if ( key == 'd' || key == 'D' ) {
  291.       first_tag += 15;
  292.       if ( ( first_tag + 15 ) >= TAG_MAX )
  293.         first_tag = TAG_MAX - 15;
  294.     }
  295.     else
  296.       break;
  297.   }
  298. }
  299.  
  300.  
  301. /*
  302.  * This routine is called when a new pointer needs to be added to the tag
  303.  * table.  It can be a maverick pointer or a regular pointer.
  304.  */
  305.  
  306. void add_tag_to_table( char far *pointer,
  307.                        char maverick,
  308.                        size_t size,
  309.                        char *file_name,
  310.                        unsigned int line_number )
  311. {
  312.   int i;
  313.  
  314.   if ( next_free_tag >= TAG_MAX )
  315.     return;
  316.   tag_table[ next_free_tag ].returned_address = pointer;
  317.   tag_table[ next_free_tag ].real_address = pointer;
  318.   tag_table[ next_free_tag ].size = size;
  319.   tag_table[ next_free_tag ].file_name = file_name;
  320.   tag_table[ next_free_tag ].line_number = line_number;
  321.   tag_table[ next_free_tag ].maverick = maverick;
  322.   if ( !maverick ) {
  323.     for ( i = 0 ; i < PICKET_SIZE ; i++ )
  324.       pointer[ i ] = leading_picket[ i ];
  325.     pointer += size;
  326.     pointer += PICKET_SIZE ;
  327.     for ( i = 0 ; i < PICKET_SIZE ; i++ )
  328.       pointer[ i ] = trailing_picket[ i ];
  329.     tag_table[ next_free_tag ].returned_address += PICKET_SIZE;
  330.   }
  331.   next_free_tag++;
  332. }
  333.  
  334.  
  335. /*
  336.  * This routine is called when a tag needs to be deleted from the table.  This
  337.  * can happen when a call to free() is made, or when a heapwalk shows that
  338.  * one of the pointers is missing.
  339.  */
  340.  
  341. void delete_tag_from_table( int tag )
  342. {
  343.   int i;
  344.  
  345.   next_free_tag--;
  346.   for ( i = tag ; i < next_free_tag ; i++ )
  347.     tag_table[ i ] = tag_table[ i + 1 ];
  348.   tag_table[ i ].returned_address = NULL;
  349.   tag_table[ i ].file_name = "Not in use";
  350.   tag_table[ i ].line_number = 0;
  351.   tag_table[ i ].size = 0;
  352. }
  353.  
  354.  
  355. /*
  356.  *  This is the verify routine that is called on the entry to my_malloc()
  357.  *  or my_free().  It calls the heap_walk() routine first, to let it do
  358.  *  its check out of the heap.  It then goes through the entire tag table
  359.  *  and verifies that the pickets are all intact.
  360.  */
  361.  
  362. void verify_heap()
  363. {
  364.   int i;
  365.   int tag;
  366.   char far *picket_pointer;
  367.  
  368.   initialize_tags();
  369.   heap_walk();
  370.   for ( tag = 0 ; tag < next_free_tag ; tag++ ) {
  371.     if ( tag_table[ tag ].maverick )
  372.       continue;
  373.     picket_pointer = tag_table[ tag ].returned_address;
  374.     picket_pointer -= PICKET_SIZE ;
  375.     for ( i = 0 ; i < PICKET_SIZE ; i++ )
  376.       if ( picket_pointer[ i ] != leading_picket[ i ] ) {
  377.         screen_message( 0, i, "Error in leading picket, tag %3d", tag );
  378.         break;
  379.       }
  380.     picket_pointer += PICKET_SIZE ;
  381.     picket_pointer += tag_table[tag].size;
  382.     for ( i = 0 ; i < PICKET_SIZE ; i++ )
  383.       if ( picket_pointer[ i ] != trailing_picket[ i ] ) {
  384.         screen_message( 0, tag, "Error in trailing picket, tag %3d", tag );
  385.         break;
  386.       }
  387.   }
  388. }
  389.  
  390. /*
  391.  * This is the routine that walks through the heap.  If an heap entry
  392.  * is not found in the tag table, a message is printed, and it is added
  393.  * as a maverick.  Otherwise, the tag is noted.  After walking through
  394.  * the whole heap, a check is done to see if any of our tagged entries
  395.  * didn't show up, which generates another message.
  396.  *
  397.  * Remember that this code is MSC-specific.  You need to rewrite this
  398.  * routine for every different compiler.
  399.  */
  400.  
  401. void heap_walk()
  402. {
  403.   struct _heapinfo hinfo;
  404.   int heapstatus;
  405.   size_t size;
  406.   int i;
  407.  
  408.   hinfo._pentry = NULL;
  409.  
  410.   for ( i = 0 ; i < next_free_tag ; i++ )
  411.     tag_table[ i ].tagged = 0;
  412.  
  413.   for ( ; ; ) {
  414.     heapstatus = _heapwalk( &hinfo );
  415.     if ( heapstatus == _HEAPEMPTY )
  416.       break;
  417.     if ( heapstatus == _HEAPEND )
  418.       break;
  419.     if ( heapstatus != _HEAPOK ) {
  420.       screen_message( 0, 0, "Heap is corrupted! Going to exit." );
  421.       exit( 1 );
  422.     }
  423.     if ( hinfo._useflag != _USEDENTRY )
  424.       continue;
  425.     for ( i = 0 ; i < next_free_tag ; i++ ) {
  426.       if ( (int far *) tag_table[ i ].real_address == hinfo._pentry ) {
  427.         tag_table[ i ].tagged = 1;
  428.         break;
  429.       }
  430.     }
  431.     if ( i == next_free_tag ) {
  432.       size = hinfo._size;
  433.       if ( i < TAG_MAX )
  434.         tag_table[ i ].tagged = 1;
  435.       add_tag_to_table( (char far *) hinfo._pentry, 1, size, "MAVERICK",0 );
  436.       screen_message( 0, i, "Found a maverick heap entry: %Fp", hinfo._pentry );
  437.     }
  438.   }
  439. /*
  440.  * At this point every entry should have been tagged, so I can go through
  441.  * the table and look for ones that didn't get tagged.
  442.  */
  443.   for ( i = 0 ; i < next_free_tag ; i++ ) {
  444.     if ( tag_table[ i ].tagged == 0 ) {
  445.       screen_message( 0, i, "Didn't find heap entry in heapwalk, tag %d", i );
  446.       delete_tag_from_table( i );
  447.     }
  448.   }
  449. }
  450.  
  451.  
  452. /*
  453.  * During the process of checking out the heap, if I see anything worthy
  454.  * of a message, I call this routine.  If the screen is not already up,
  455.  * this guy pulls it up.  Then it prints the message.
  456.  */
  457.  
  458. void screen_message( int immediate_return, int tag, char *format, ... )
  459. {
  460.   char message[ 81 ];
  461.   va_list args;
  462.  
  463.   if ( screen_up == 0 ) {
  464.     screen_up = 1;
  465.     message_line = 20;
  466.     setup_screen( labels, widths, 15 );
  467.   }
  468.   va_start( args, format );
  469.   vsprintf( message, format, args );
  470.   screenputs( message_line, 0, message );
  471.   if ( ++message_line >= 25 )
  472.     message_line = 20;
  473.   if ( !immediate_return )
  474.     display_tag_table( tag );
  475. }
  476.  
  477. /*
  478.  * After all the work is done, I have to hide my heap screen so the user
  479.  * can see the application output.  This is pretty easy to do, a routine
  480.  * in SCREEN.C does the whole job for me.
  481.  */
  482. void hide_screen()
  483. {
  484.   if ( screen_up != 0 ) {
  485.     screen_up = 0;
  486.     restore_screen();
  487.   }
  488. }
  489.  
  490.  
  491.  
  492. *********************************SCREEN.C***************************************
  493.  
  494. /*
  495.  * Author:       Mark Nelson
  496.  *
  497.  * Date:         October 28, 1989
  498.  *
  499.  * Description:  This module contains the screen I/O routines used in
  500.  *               the heap debugger module.  These are very simplified
  501.  *               screen I/O routines.
  502.  */
  503.  
  504. #include <stdio.h>
  505. #include <stdarg.h>
  506. #include <string.h>
  507. #include "_heap.h"
  508. /*
  509.  * These are all the line drawing constants defined.
  510.  */
  511. #define UL_CORNER       218
  512. #define UR_CORNER       191
  513. #define LL_CORNER       192
  514. #define LR_CORNER       217
  515. #define UPPER_TEE       194
  516. #define LOWER_TEE       193
  517. #define LEFT_TEE        195
  518. #define RIGHT_TEE       180
  519. #define CENTER_TEE      197
  520. #define HORIZONTAL_LINE 196
  521. #define VERTICAL_LINE   179
  522.  
  523. /*
  524.  * I create a structure so I can write directly to screen as if it were
  525.  * a big array.  That way the compiler takes care of computing the
  526.  * addresses, all I have to do is insert the row and column.
  527.  */
  528. struct video_element {
  529.                           unsigned char character;
  530.                           unsigned char attribute;
  531.                      };
  532. struct video_element (far *physical_screen)[25][80];
  533. struct video_element saved_screen[25][80];
  534.  
  535. /*
  536.  * This routine draws the box I use up on the screen.  It is passed a
  537.  * list of labels to draw at the head of the columns, plus a count
  538.  * of how many rows are to be left open for data entry.  It depends
  539.  * on some earlier code somewhere to have initialized an array called
  540.  * columns[] that tells it where to draw each column on the screen.
  541.  * There is a lot of code here to draw the boxes, but it is all
  542.  * straightforward.
  543.  */
  544. int columns[10];
  545. int column_count=0;
  546.  
  547. void draw_boxes_and_titles(char *labels[],int row_count)
  548. {
  549. int col;
  550. int row;
  551. int i;
  552. int j;
  553. int rows[3];
  554. /*
  555.  * The three rows I define are the top and bottom of the box, plus the
  556.  * line that divides the title lines from the data lines.
  557.  */
  558.     rows[0]=0;
  559.     rows[1]=2;
  560.     rows[2]=3+row_count;
  561.     for (col=1;col<columns[column_count];col++)
  562.         for (i=0;i<3;i++)
  563.             (*physical_screen)[rows[i]][col].character = HORIZONTAL_LINE;
  564.     for (i=0;i<=column_count;i++)
  565.         for (row=0;row<(row_count+4);row++)
  566.             (*physical_screen)[row][columns[i]].character = VERTICAL_LINE;
  567.     (*physical_screen)[0][columns[0]].character = UL_CORNER;
  568.     (*physical_screen)[row_count+3][columns[0]].character = LL_CORNER;
  569.     (*physical_screen)[0][columns[column_count]].character = UR_CORNER;
  570.     (*physical_screen)[row_count+3][columns[column_count]].character = LR_CORNER;
  571.  
  572.     (*physical_screen)[rows[1]][columns[0]].character = LEFT_TEE;
  573.     (*physical_screen)[rows[1]][columns[column_count]].character = RIGHT_TEE;
  574.     for (j=1;j<column_count;j++)
  575.         (*physical_screen)[0][columns[j]].character = UPPER_TEE;
  576.     for (j=1;j<column_count;j++)
  577.         (*physical_screen)[row_count+3][columns[j]].character = LOWER_TEE;
  578.  
  579.     for (j=1;j<column_count;j++)
  580.         (*physical_screen)[rows[1]][columns[j]].character = CENTER_TEE;
  581. /*
  582.  * Here is where I draw the labels.  They need to go in the center of
  583.  * their little boxes.
  584.  */
  585.     for (i=0;i<column_count;i++)
  586.     {
  587.         col=columns[i]+1;
  588.         col += (columns[i+1]-columns[i]-1)/2;
  589.         col -= strlen(labels[i])/2;
  590.         screenputs(1,col,labels[i]);
  591.     }
  592. }
  593. /*
  594.  * This is a general purpose routine to print a formatted string on
  595.  * the screen.
  596.  */
  597. void screenputf(int row,int col,char *format,...)
  598. {
  599.     char buffer[81];
  600.     va_list args;
  601.  
  602.     va_start(args,format);
  603.     vsprintf(buffer,format,args);
  604.     screenputs(row,col,buffer);
  605. }
  606. /*
  607.  * This is a general purpose routine to put an unformatted string
  608.  * out to the screen.
  609.  */
  610. void screenputs(int row,int col,char *string)
  611. {
  612. char c;
  613.  
  614.     while (1)
  615.     {
  616.         c=*string++;
  617.         if (c=='\0')
  618.             break;
  619.         (*physical_screen)[row][col++].character=c;
  620.     }
  621. }
  622. /*
  623.  * This is a general purpose routine to clear a whole line on the
  624.  * screen.
  625.  */
  626. void screenclearline(int row)
  627. {
  628. int col;
  629.  
  630.     for (col=0;col<80;col++)
  631.         (*physical_screen)[row][col].character=' ';
  632. }
  633. /*
  634.  * This is the screen initialization code.  It is a trap door routine that
  635.  * gets called all the time, but only executes once.  It computes what
  636.  * columns the vertical lines are going to go in, based on the widths needed
  637.  * for each column, passed as a parameter.
  638.  * Note that if you are using a monochrome monitor, you need to change
  639.  * the screen pointer to be 0xb0000000L.
  640.  * This routine also initializes the tag table
  641.  */
  642. void initialize_screen(char *labels[],int widths[])
  643. {
  644. int row;
  645. int col;
  646. int i;
  647. static int first_time=0;
  648.  
  649.     if (first_time==0)
  650.     {
  651.         first_time=1;
  652.         columns[0]=1;
  653.         column_count=0;
  654.         while (strlen(labels[column_count]) != 0)
  655.         {
  656.             columns[column_count+1] = columns[column_count]+widths[column_count]+1;
  657.             column_count++;
  658.         }
  659.     }
  660.     physical_screen=(struct video_element (far *)[25][80])0xb8000000L;
  661.     for (row=0;row<25;row++)
  662.         for (col=0;col<80;col++)
  663.         {
  664.              saved_screen[row][col]=(*physical_screen)[row][col];
  665.              (*physical_screen)[row][col].character=' ';
  666.              (*physical_screen)[row][col].attribute=0x1b;
  667.         }
  668. }
  669.  
  670. /*
  671.  *  Whenever the heap routines decide they need to print a screen message,
  672.  *  they set up the screen first by calling this guy.
  673.  */
  674. void setup_screen(char *labels[],int widths[],int rows)
  675. {
  676.     initialize_screen(labels,widths);
  677.     draw_boxes_and_titles(labels,rows);
  678. }
  679.  
  680. /*
  681.  * After the heap routines are done printing debug information, they
  682.  * have to restore the screen back to where it was when they got called.
  683.  * This routine does that.
  684.  */
  685. void restore_screen()
  686. {
  687. int row;
  688. int col;
  689.  
  690.     for (row=0;row<25;row++)
  691.         for (col=0;col<80;col++)
  692.              (*physical_screen)[row][col]=saved_screen[row][col];
  693. }
  694.  
  695. *********************************_HEAP.H****************************************
  696.  
  697. /* Prototypes from SCREEN.C  */
  698.  
  699. void draw_boxes_and_titles(char *labels[],int row_count);
  700. void screenputc(int row,int col,char c);
  701. void screenputf(int row,int col,char *format,...);
  702. void screenputs(int row,int col,char *string);
  703. void screenclearline(int row);
  704. void initialize_screen(char *labels[],int widths[]);
  705. void setup_screen(char *labels[],int widths[],int rows);
  706. void restore_screen(void);
  707.  
  708. /* Prototypes from HEAP.C */
  709.  
  710. void screen_message(int immediate_return, int tag, char *format,...);
  711. void hide_screen(void);
  712. void my_free(char *file_name,unsigned int line_number, void *block);
  713. void *my_malloc(char *file_name,unsigned int line_number,size_t size);
  714. void initialize_tags(void);
  715. void display_tag_table(int last_tag);
  716. void add_tag_to_table(char far *pointer,char maverick,size_t size,char *file_name,unsigned int line_number);
  717. void delete_tag_from_table(int tag);
  718. void verify_heap(void);
  719. void heap_walk(void);
  720.